// FileName : happyballot.cpp
// Implementation of class HappyBallot

#include "happyballot.h"
#include <sstream>
#include <iostream>

const string HappyBallot::HOST = "localhost";
const string HappyBallot::USERNAME = "zpw";
const string HappyBallot::PASSWORD = "zpw123456";
const string HappyBallot::DBNAME = "test";
const unsigned int HappyBallot::PORT = 3309;
const unsigned int HappyBallot::INTERVAL = 5;

HappyBallot::HappyBallot() {
	//mysql_library_init(); //what is the paramters?
	
	mysql_init(&mysql);

	mysqlPoint = mysql_real_connect( &mysql, HOST.c_str(), USERNAME.c_str(), PASSWORD.c_str(),
		DBNAME.c_str(), PORT, NULL, CLIENT_FOUND_ROWS );
		
}

HappyBallot::~HappyBallot() {
	if ( mysqlPoint != NULL ) {
		mysql_close( mysqlPoint );
	}
}


// return -1 for database error
// 		   1 for success
int
HappyBallot::getNumberOfComments( int &numberOfComments ) {
	if ( !mysqlPoint ) {
		return -1;
	}

	string queryStr = "select total from totalMessages where id=0";

	if ( mysql_query( mysqlPoint, queryStr.c_str() ) ) {
		return -1;
	}

	MYSQL_RES *result = mysql_store_result( mysqlPoint );

	if ( result ) {
		MYSQL_ROW row = mysql_fetch_row ( result );
		istringstream inStr( row[0] );
		inStr >> numberOfComments;
	}
	else {
		return -1;
	}

	mysql_free_result( result );

	return 1;
}

int
HappyBallot::getComments( int startNo, int length, string *ips, string *comments ) {
	if ( !mysqlPoint ) {
		return -1;
	}

	ostringstream outStr;
	outStr << "select ip, msg from messages limit "
		   << startNo
		   << ","
		   << length;

	string queryStr = outStr.str();
	
	if ( mysql_query( mysqlPoint, queryStr.c_str() ) ) {
		return -1;
	}

	MYSQL_RES *result = mysql_store_result( mysqlPoint );
	if ( result ) {
		MYSQL_ROW row;
		for ( int i = 0; i < length; i ++ ) {
			row = mysql_fetch_row( result );
			ips[i] = row[0];
			comments[i] = row[1];
		}
	}
	else {
		return -1;
	}

	mysql_free_result( result );

	return 1;
}

// return: 1 for success ballot;
//		   0 for time between twice ballots is lower than one hour
//		  -1 for database error
//		  -2 for a invalid input
int
HappyBallot::ballot( int girlsNumber, string IP, string message ) {
	ostringstream outStream;
	ostringstream logStream;
	unsigned long interval = 0;

	if ( !mysqlPoint ) {
		return -1;
	} 
	
	char * ipBuffer = new char[ IP.length() * 2 + 1 ];
	mysql_real_escape_string( mysqlPoint, ipBuffer, IP.c_str(), IP.length() );
	
	outStream << "select time from IPs where ip=\'"
		   	  << ipBuffer
		      << "\'";

	string queryStr = outStream.str();

	if ( mysql_query( mysqlPoint, queryStr.c_str() ) ) {
		return -1;
	}

	MYSQL_RES *result = mysql_store_result( mysqlPoint );
	bool couldBallot;
	bool newIP = false;
	unsigned long current = 0;
	unsigned long last = 0;

	if ( result ) {
		int numRows = mysql_num_rows( result );

		if ( numRows == 0 ) {
			couldBallot = true;
			newIP = true;
		} else {
			MYSQL_ROW row = mysql_fetch_row ( result );
			time_t currentTime = time( NULL );
			istringstream inStr( row[0] );
			unsigned long lastTime;
			inStr >> lastTime;
			interval = currentTime - lastTime;
			current = currentTime;
			last = lastTime;
			if ( interval > INTERVAL ) {
				couldBallot = true;
			}
			else {
				couldBallot = false;
			}
		}
	}
	else {
		// A select query must return something, if not 
		// there may be some error!
		return -1;
	}

	mysql_free_result( result );

//	logStream << "insert into log values(\'" << IP << " " << girlsNumber 
//			  << " " << couldBallot << " " << interval << " " << current 
//			  << " " << last << "\')";

//	mysql_query( mysqlPoint, logStream.str().c_str() );
	
	if ( couldBallot ) {
		return ballotModifyDB( girlsNumber, IP, message, newIP );
	}
	else {
		return 0;
	}
}


// return : -1 for DB errer
//			 1 for success
// input  :  must be the same with database records
int
HappyBallot::getCurrentResult( long * resultArray ) {
	if ( !mysqlPoint ) {
		return -1;
	}

	string queryStr("select numOfBallot from HappyGirls;");

	if ( mysql_query( mysqlPoint, queryStr.c_str() ) ) {
		return -1;
	}

	MYSQL_RES *result = mysql_store_result( mysqlPoint );
	if ( result ) {
		MYSQL_ROW row;
		int i = 0;

		while ( row = mysql_fetch_row( result ) ) {
			istringstream inStr(row[0]);
			inStr >> resultArray[i];
			i++; 
		}
		
		mysql_free_result( result );
	}
	else {
		return -1;
	}

	return 1;
}

bool
HappyBallot::doBeforeAccessDB( string queryString ) {
	if( queryString.size() > 70) {
		return false;
	}

	return true;
}

// return: 1 for success ballot;
//		  -1 for database error
//		  -2 for a invalid input
int
HappyBallot::ballotModifyDB( int girlsNum, string IP, string message, bool newIP ) {
	ostringstream outStr;
	outStr << "update HappyGirls set numOfBallot=numOfBallot+1 where id="
		   << girlsNum
		   << " or id=8";

	if ( !mysqlPoint ) {
		return -1;
	}
	
	string queryStr = outStr.str();
	
	bool result = doBeforeAccessDB( queryStr );

	if( result == false )
		return -2;

	if ( mysql_query( mysqlPoint, queryStr.c_str() ) ) {
		return -1;
	}

	outStr.str("");
	time_t currentTime = time( NULL );
	if ( newIP ) {
		outStr << "insert into IPs values( \'"
			   << IP
			   << "\', "
			   << (unsigned long)currentTime
			   << ")";
		
		queryStr = outStr.str();

		if ( mysql_query( mysqlPoint, queryStr.c_str() ) ) {
			return -1;
		}
	}
	else {
		outStr << "update IPs set time="
			   << (unsigned long)currentTime
			   << " where ip=\'"
			   << IP
			   << "\'";

		queryStr = outStr.str();

		if ( mysql_query( mysqlPoint, queryStr.c_str() ) ) {
			return -1;
		}
	}

	if ( message.length() > 200 ) {
		message = message.substr( 0, 200 );
	}

	char * messageBuffer = new char[ message.length() * 2 + 1 ];

	mysql_real_escape_string( mysqlPoint, messageBuffer, message.c_str(), message.length() );
	outStr.str("");
	outStr << "insert into messages ( ip, msg ) values (\'"
		   << IP << "\', \'"
		   << messageBuffer
		   << "\' )";


	queryStr = outStr.str();
	if ( mysql_query( mysqlPoint, queryStr.c_str() ) ) {
		return -1;
	}

	return 1;
}

// End of happyballot.cpp
